package com.killer_jin.core.common.util.auth;

import com.killer_jin.core.common.exception.AuthFaildException;
import io.jsonwebtoken.*;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * JWT token 生成与验证
 *
 * @author jiayu
 * @since 2019/07/10
 */
public class TokenAuthenticater {
    // 过期时间, 默认1天
    private static final long EXPIRE = 86_400_000L;
    // JWT secret
    private static final String SECRET = "P@ssw02d";
    // Token前缀
    private static final String TOKEN_PREFIX = "Bearer";
    // 存放Token的Header Key
    private static final String HEADER_STRING = "Authorization";
    // Token key,
    private static final String TOKEN_KEY = "accountCenterToken";

    /**
     * 生成通用JWT token
     *
     * @param userId 用户id
     * @return JWT String
     */
    public static String buildJWT(String userName, String userId) {
        return Jwts.builder()
                // 保存权限（角色）
                .claim("authorities", "ROLE_ADMIN,AUTH_WRITE")
                // 用户名写入标题
                .setSubject(userName)
                .setId(userId)
                // 有效期设置
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                // 签名设置
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
    }

    /**
     * 特殊用户JWT验证(需要验证TOKEN_KEY)
     *
     * @param request http请求
     * @return Authentication
     */
    public static Authentication getSpecialAuthentication(HttpServletRequest request) {
        // 从Header中拿到token
        String token = request.getHeader(HEADER_STRING);

        if (token != null && !"".equals(token)) {
            // 解析 Token
            try {
                Claims claims = getClaims(token);
                // 拿用户名
                String username = claims.getSubject();
                // 得到 权限（角色）
                List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("authorities"));
                if (Objects.isNull(claims.get(TOKEN_KEY))) {
                    return null;
                }
                // 返回验证令牌
                String customerId = claims.getId();
                return username != null ? new UsernamePasswordAuthenticationToken(customerId, claims.get(TOKEN_KEY), authorities) : null;
            } catch (MalformedJwtException ex) {
                throw new AuthFaildException("登录信息无效，请重试！");
            } catch (ExpiredJwtException ex) {
                throw new AuthFaildException("登录信息过期，请重新登录！");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 通用用户JWT验证
     *
     * @param request http请求
     * @return Authentication
     */
    public static Authentication getCommonAuthentication(HttpServletRequest request) {
        // 从Header中拿到token
        String token = request.getHeader(HEADER_STRING);

        if (token != null) {
            try {
                // 解析 Token
                Claims claims = getClaims(token);

                // 拿用户名
                String username = claims.getSubject();

                // 得到 权限（角色）
                List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("authorities"));

                // 返回验证令牌
                String customerId = claims.getId();
                return username != null ? new UsernamePasswordAuthenticationToken(customerId, null, authorities) : null;
            } catch (MalformedJwtException ex) {
                throw new AuthFaildException("登录信息无效，请重试！");
            } catch (ExpiredJwtException ex) {
                throw new AuthFaildException("登录信息过期，请重新登录！");
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return null;
    }

    /**
     * 获取Claims
     *
     * @param token token
     * @return Claims
     */
    private static Claims getClaims(String token) {
        return Jwts.parser()
                // 验签
                .setSigningKey(SECRET)
                // 去掉 Bearer
                .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                .getBody();
    }

}